import { _decorator, Component, Vec2, Vec3, Graphics, Node, Input, Prefab, instantiate, log } from 'cc';
import { paragraph } from './paragraph';
import { StorageUtil } from './StorageUtil';
import EventMgr from './EventManager';
import { EventType } from './enumType';
const { ccclass, property } = _decorator;

@ccclass('BezierCurveTool')
export class BezierCurveTool extends Component {
    @property(Prefab) paragraph: Prefab | null = null;
    
    controlNodeGroups: Node[] = [];
    graphics: Graphics | null = null;

    // 绘制步数
    @property
    steps: number = 100;

    // 吸附阈值
    @property
    snapThreshold: number = 20;

    private savedPath: { x: number; y: number }[][] = [
        [
            { x: 0, y: 0 },
            { x: 50, y: 100 },
            { x: 100, y: 0 }
        ],
        [
            { x: 100, y: 0 },
            { x: 150, y: -100 },
            { x: 200, y: 0 }
        ]
    ];

    protected onLoad(): void {
        EventMgr.Instance.on(EventType.drawBezierCurves, this.drawBezierCurves, this);
    }

    protected onDestroy(): void {
        EventMgr.Instance.off(EventType.drawBezierCurves, this.drawBezierCurves);
    }

    start() {
        this.controlNodeGroups = this.node.children;
        this.graphics = this.getComponent(Graphics);
        if (this.graphics) {
            this.drawBezierCurves(false);
            // this.drawPoint(Vec2.ZERO);
        }
    }

    drawPoint(position: Vec2) {
        // 绘制一个小矩形来模拟点
        const pointSize = 50;
        this.graphics.rect(position.x - pointSize / 2, position.y - pointSize / 2, pointSize, pointSize);
        log("绘制点", position);
        this.graphics.fill();
        
    }

    drawBezierCurves(TestPath:boolean = true) {

        this.graphics!.clear();

        if(TestPath){
            log("TestPath");
            // 调试贝塞尔曲线
            for (const controlNodes of this.controlNodeGroups) {
                if (controlNodes.children.length < 2) {
                    continue;
                }

                // 检查吸附
                this.checkSnap(controlNodes.children[0]);
                this.checkSnap(controlNodes.children[controlNodes.children.length - 1]);

                for (let i = 0; i < this.steps; i++) {
                    const t1 = i / this.steps;
                    const t2 = (i + 1) / this.steps;

                    const p1 = this.getBezierPoint_node(controlNodes.children, t1);
                    const p2 = this.getBezierPoint_node(controlNodes.children, t2);

                    if (i === 0) {
                        this.graphics!.moveTo(p1.x, p1.y);
                    }
                    this.graphics!.lineTo(p2.x, p2.y);
                }
            }
            this.graphics!.stroke();
        }else{
            log("TestPath is false");
            this.node.removeAllChildren();
            const savedPath = StorageUtil.getObj("BallPath",this.savedPath);
            // 绘制保存的路径
            for (const curvePoints of savedPath) {
                if (curvePoints.length < 2) {
                    continue;
                }
                for (let i = 0; i < this.steps; i++) {
                    const t1 = i / this.steps;
                    const t2 = (i + 1) / this.steps;
    
                    const p1 = this.getBezierPoint_pos(curvePoints, t1);
                    const p2 = this.getBezierPoint_pos(curvePoints, t2);
    
                    if (i === 0) {
                        this.graphics.moveTo(p1.x, p1.y);
                    }
                    this.graphics.lineTo(p2.x, p2.y);
                }
            }
    
            this.graphics.stroke();
        }
        
    }

    getBezierPoint_node(controlNodes: Node[], t: number): Vec2 {
        const n = controlNodes.length - 1;
        let result = new Vec2(0, 0);
        for (let i = 0; i <= n; i++) {
            const binomialCoefficient = this.binomialCoefficient(n, i);
            const term = binomialCoefficient * Math.pow(1 - t, n - i) * Math.pow(t, i);
            const nodePos = controlNodes[i].position;
            result.x += term * nodePos.x;
            result.y += term * nodePos.y;
        }
        return result;
    }

    getBezierPoint_pos(curvePoints: { x: number; y: number }[], t: number): Vec2 {
        const n = curvePoints.length - 1;
        let result = new Vec2(0, 0);
        for (let i = 0; i <= n; i++) {
            const binomialCoefficient = this.binomialCoefficient(n, i);
            const term = binomialCoefficient * Math.pow(1 - t, n - i) * Math.pow(t, i);
            result.x += term * curvePoints[i].x;
            result.y += term * curvePoints[i].y;
        }
        return result;
    }

    binomialCoefficient(n: number, k: number): number {
        let result = 1;
        for (let i = 1; i <= k; i++) {
            result *= (n - (k - i)) / i;
        }
        return result;
    }

    addControlNode() {
        const len = this.controlNodeGroups.length.toString();
        const newNode = instantiate(this.paragraph);
        newNode.parent = this.node;
        newNode.getComponent(paragraph).labelStr = len;
        this.scheduleOnce(() => {
            this.drawBezierCurves();
        }, 0.1);
    }

    removeControlNode() {
        if (this.controlNodeGroups.length > 0) {
            const lastGroup = this.controlNodeGroups[this.controlNodeGroups.length - 1];
            lastGroup.destroy();
            this.scheduleOnce(() => {
                this.drawBezierCurves();
            }, 0.1);
        }
    }

    // 检查吸附
    checkSnap(target: Node) {
        const targetParent = target.parent;
        if (!targetParent) return;

        const targetIndex = targetParent.children.indexOf(target);
        if (targetIndex !== 0 && targetIndex !== targetParent.children.length - 1) return;

        for (const controlNodes of this.controlNodeGroups) {
            if (controlNodes === targetParent) continue;

            const startNode = controlNodes.children[0];
            const endNode = controlNodes.children[controlNodes.children.length - 1];

            const distanceToStart = Vec3.distance(target.position, startNode.position);
            const distanceToEnd = Vec3.distance(target.position, endNode.position);

            if (distanceToStart < this.snapThreshold) {
                target.setPosition(startNode.position);
            } else if (distanceToEnd < this.snapThreshold) {
                target.setPosition(endNode.position);
            }
        }
    }

    // 获取所有曲线的控制点组
    getControlNodeGroups() {
        return this.controlNodeGroups;
    }

    // 保存路径
    savePath() {
        const path = [];
        for (const controlNodes of this.controlNodeGroups) {
            const curvePoints = [];
            for (const node of controlNodes.children) {
                curvePoints.push({ x: node.position.x, y: node.position.y });
            }
            path.push(curvePoints);
        }
        StorageUtil.setObj("BallPath",path);
        return path;
    }
}